home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / e33el2.zip / emacs / 19.33 / lisp / ielm.el < prev    next >
Lisp/Scheme  |  1996-01-20  |  18KB  |  472 lines

  1. ;;; ielm.el --- interaction mode for Emacs Lisp
  2.  
  3. ;; Copyright (C) 1994 Free Software Foundation, Inc.
  4.  
  5. ;; Author: David Smith <maa036@lancaster.ac.uk>
  6. ;; Created: 25 Feb 1994
  7. ;; Keywords: lisp
  8.  
  9. ;; This file is part of GNU Emacs.
  10.  
  11. ;; GNU Emacs is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 2, or (at your option)
  14. ;; any later version.
  15.  
  16. ;; GNU Emacs is distributed in the hope that it will be useful,
  17. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. ;; GNU General Public License for more details.
  20.  
  21. ;; You should have received a copy of the GNU General Public License
  22. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  23. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  24. ;; Boston, MA 02111-1307, USA.
  25.  
  26. ;;; Commentary:
  27.  
  28. ;; Provides a nice interface to evaluating Emacs Lisp expressions.
  29. ;; Input is handled by the comint package, and output is passed
  30. ;; through the pretty-printer.
  31.  
  32. ;; To install: copy this file to a directory in your load-path, and
  33. ;; add the following line to your .emacs file:
  34. ;;
  35. ;;   (autoload 'ielm "ielm" "Start an inferior Emacs Lisp session" t)
  36. ;;
  37. ;; For completion to work, the comint.el from FSF Emacs 19.23 is
  38. ;; required.  If you do not have it, or if you are running Lemacs,
  39. ;; also add the following code to your .emacs:
  40. ;;
  41. ;;    (setq ielm-mode-hook
  42. ;;         '(lambda nil
  43. ;;          (define-key ielm-map "\t"
  44. ;;             '(lambda nil (interactive) (or (ielm-tab) 
  45. ;;                                                 (lisp-complete-symbol))))))
  46.  
  47. ;; To start: M-x ielm.  Type C-h m in the *ielm* buffer for more info.
  48.  
  49. ;; The latest version is available by WWW from 
  50. ;;      http://mathssun5.lancs.ac.uk:2080/~maa036/elisp/dir.html
  51. ;; or by anonymous FTP from
  52. ;;      /anonymous@wingra.stat.wisc.edu:pub/src/emacs-lisp/ielm.el.gz
  53. ;; or from the author: David M. Smith <maa036@lancaster.ac.uk>
  54.  
  55. ;;; Code:
  56.  
  57. (require 'comint)
  58. (require 'pp)
  59.  
  60. ;;; User variables
  61.  
  62. (defvar ielm-noisy t
  63.   "*If non-nil, IELM will beep on error.")
  64.  
  65. (defvar ielm-prompt "ELISP> "
  66.   "Prompt used in IELM.")
  67.  
  68. (defvar ielm-dynamic-return t
  69.   "*Controls whether \\<ielm-map>\\[ielm-return] has intelligent behaviour in IELM.
  70. If non-nil, \\[ielm-return] evaluates input for complete sexps, or inserts a newline
  71. and indents for incomplete sexps.  If nil, always inserts newlines.")
  72.  
  73. (defvar ielm-dynamic-multiline-inputs t
  74.   "*Force multiline inputs to start from column zero?
  75. If non-nil, after entering the first line of an incomplete sexp, a newline
  76. will be inserted after the prompt, moving the input to the next line.
  77. This gives more frame width for large indented sexps, and allows functions
  78. such as `edebug-defun' to work with such inputs.")
  79.  
  80. (defvar ielm-mode-hook nil
  81.   "*Hooks to be run when IELM (`inferior-emacs-lisp-mode') is started.")
  82.  
  83. ;;; System variables
  84.  
  85. (defvar ielm-working-buffer nil
  86.   "Buffer in which IELM sexps will be evaluated.
  87. This variable is buffer-local.")
  88.  
  89. (defvar ielm-header 
  90.   (concat
  91.    "*** Welcome to IELM version "
  92.    (substring "$Revision: 1.7 $" 11 -2)
  93.    " ***  Type (describe-mode) for help.\n"
  94.    "IELM has ABSOLUTELY NO WARRANTY; type (describe-no-warranty) for details.\n")
  95.   "Message to display when IELM is started.")
  96.  
  97. (defvar ielm-map nil)
  98. (if ielm-map nil
  99.   (if (string-match "Lucid" emacs-version)
  100.       ;; Lemacs
  101.       (progn
  102.     (setq ielm-map (make-sparse-keymap))
  103.     (set-keymap-parent ielm-map comint-mode-map))
  104.     ;; FSF
  105.     (setq ielm-map (cons 'keymap comint-mode-map)))
  106.   (define-key ielm-map "\t" 'comint-dynamic-complete)
  107.   (define-key ielm-map "\C-m" 'ielm-return)
  108.   (define-key ielm-map "\C-j" 'ielm-send-input)
  109.   (define-key ielm-map "\e\C-x" 'eval-defun)         ; for consistency with
  110.   (define-key ielm-map "\e\t" 'lisp-complete-symbol) ; lisp-interaction-mode
  111.   ;; These bindings are from shared-lisp-mode-map -- can you inherit
  112.   ;; from more than one keymap??
  113.   (define-key ielm-map "\e\C-q" 'indent-sexp)      
  114.   (define-key ielm-map "\eq" 'lisp-fill-paragraph) 
  115.   (define-key ielm-map "\177" 'backward-delete-char-untabify)
  116.   ;; Some convenience bindings for setting the working buffer
  117.   (define-key ielm-map "\C-c\C-b" 'ielm-change-working-buffer)
  118.   (define-key ielm-map "\C-c\C-f" 'ielm-display-working-buffer)
  119.   (define-key ielm-map "\C-c\C-v" 'ielm-print-working-buffer))
  120.  
  121. (defvar ielm-font-lock-keywords
  122.   (list 
  123.    (cons (concat "^" (regexp-quote ielm-prompt)) 'font-lock-keyword-face)
  124.    '("\\(^\\*\\*\\*[^*]+\\*\\*\\*\\)\\(.*$\\)" (1 font-lock-comment-face) (2 font-lock-reference-face)))
  125.   "Additional expressions to highlight in ielm buffers.")
  126.     
  127. ;;; Completion stuff
  128.  
  129. (defun ielm-tab nil
  130.   "Possibly indent the current line as lisp code."
  131.   (interactive)
  132.   (if (or (eq (preceding-char) ?\n)
  133.       (eq (char-syntax (preceding-char)) ? ))
  134.       (progn
  135.     (ielm-indent-line)
  136.     t)))
  137.   
  138. (defun ielm-complete-symbol nil
  139.   "Complete the lisp symbol before point."
  140.   ;; A wrapper for lisp-complete symbol that returns non-nil if
  141.   ;; completion has occurred
  142.   (let* ((btick (buffer-modified-tick))
  143.      (cbuffer (get-buffer "*Completions*"))
  144.      (ctick (and cbuffer (buffer-modified-tick cbuffer))))
  145.     (lisp-complete-symbol)
  146.      ;; completion has occurred if:
  147.     (or 
  148.      ;; the buffer has been modified
  149.      (not (= btick (buffer-modified-tick))) 
  150.      ;; a completions buffer has been modified or created
  151.      (if cbuffer
  152.      (not (= ctick (buffer-modified-tick cbuffer)))
  153.        (get-buffer "*Completions*")))))
  154.  
  155. (defun ielm-complete-filename nil
  156.   "Dynamically complete filename before point, if in a string."
  157.   (if (nth 3 (parse-partial-sexp comint-last-input-start (point)))
  158.       (comint-dynamic-complete-filename)))
  159.      
  160. (defun ielm-indent-line nil
  161.   "Indent the current line as Lisp code if it is not a prompt line."
  162.   (if (save-excursion
  163.     (beginning-of-line)
  164.     (looking-at comint-prompt-regexp)) nil
  165.     (lisp-indent-line)))
  166.  
  167. ;;; Working buffer manipulation
  168.  
  169. (defun ielm-print-working-buffer nil
  170.   "Print the current IELM working buffer's name in the echo area."
  171.   (interactive)
  172.   (message "The current working buffer is: %s" (buffer-name ielm-working-buffer)))
  173.  
  174. (defun ielm-display-working-buffer nil
  175.   "Display the current IELM working buffer.
  176. Don't forget that selecting that buffer will change its value of `point'
  177. to its value of `window-point'!"
  178.   (interactive)
  179.   (display-buffer ielm-working-buffer)
  180.   (ielm-print-working-buffer))
  181.  
  182. (defun ielm-change-working-buffer (buf)
  183.   "Change the current IELM working buffer to BUF.
  184. This is the buffer in which all sexps entered at the IELM prompt are
  185. evaluated.  You can achieve the same effect with a call to
  186. `set-buffer' at the IELM prompt."
  187.   (interactive "bSet working buffer to: ")
  188.   (setq ielm-working-buffer (or (get-buffer buf) (error "No such buffer")))
  189.   (ielm-print-working-buffer))
  190.  
  191. ;;; Other bindings
  192.  
  193. (defun ielm-return nil
  194.   "Newline and indent, or evaluate the sexp before the prompt.
  195. Complete sexps are evaluated; for incomplete sexps inserts a newline
  196. and indents.  If however `ielm-dynamic-return' is nil, this always
  197. simply inserts a newline."
  198.   (interactive)
  199.   (if ielm-dynamic-return 
  200.       (let ((state       
  201.          (save-excursion
  202.            (end-of-line)
  203.            (parse-partial-sexp (ielm-pm)
  204.                    (point)))))
  205.     (if (and (< (car state) 1) (not (nth 3 state)))
  206.         (ielm-send-input)
  207.       (if (and ielm-dynamic-multiline-inputs
  208.            (save-excursion
  209.              (beginning-of-line)
  210.              (looking-at comint-prompt-regexp)))
  211.           (save-excursion
  212.         (goto-char (ielm-pm))
  213.         (newline 1)))
  214.       (newline-and-indent)))
  215.     (newline)))
  216.  
  217. (defun ielm-input-sender (proc input)
  218.   ;; Just sets the variable ielm-input, which is in the scope of 
  219.   ;; `ielm-send-input's call.
  220.   (setq ielm-input input))
  221.  
  222. (defun ielm-send-input nil
  223.   "Evaluate the Emacs Lisp expression after the prompt."
  224.   (interactive)
  225.   (let ((buf (